package com.trg.flex {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	import mx.binding.utils.ChangeWatcher;
	import mx.events.PropertyChangeEvent;
	import mx.events.PropertyChangeEventKind;
	
	/**
	 * <p>This class was created to deal with a problem which arose from having NestedFieldColumns.
	 * The problem was the lists were showing values of properties within properties, but when
	 * those properties within properties were changed, the change event did not bubble all the way
	 * up to the list for it to know to re-render.
	 * 
	 * <p>If a class extends this ChangeInheritor, it can be configured to fire a property change
	 * event if one of its properties fires a property change event. This way the event makes it
	 * all the way up to the list no matter how far down the change is as long as this ChangeInheritor
	 * is set up at each step along the way.
	 * 
	 * <p>To configure a class that extends ChangeInheritor, call the <code>inheritChanges<code> method
	 * and pass in a string which is the name of the property to inherit changes from. This can be
	 * called multiple times for different properties to set all of them up. It probably makes most
	 * sense to make these <code>inheritChanges<code> calls in the constructor.
	 * 
	 * <p>For example:
	 * <pre>
	 * public class OwnerVO() {
	 *   public function OwnerVO() {
	 *     inheritChanges("type");
	 *   }
	 * 
	 *   [Bindable]
	 *   public var type:TypeVO;
	 * }
	 * </pre>
	 * 
	 * <p>As compared to an implementatin with ChangeWatchers, this does not catch manual bindings
	 * but it is more efficient. This also does not allow specifying which property changes to "inherit"
	 */
	public class ChangeInheritor extends EventDispatcher
	{
		private var props:Dictionary = new Dictionary();
		
		protected function inheritChanges(prop:String):void {
			props[prop] = this[prop];
			ChangeWatcher.watch(this, prop, inheritingPropertySet)
		}
		
		private function inheritingPropertySet(evt:PropertyChangeEvent):void {
			for (var prop:String in props) {
				var value:* = this[prop];
				var prev:* = props[prop];
				if (value !== prev) {
					if (prev != null) {
						try {
							prev.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, dispatchInheritedChange);
						} catch (e:Error) {}
					}
					if (value != null) {
						try {
							value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, dispatchInheritedChange);
						} catch (e:Error) {}
					}
				}
			}
		}
		
		private function dispatchInheritedChange(evt:Event):void {
			dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, PropertyChangeEventKind.UPDATE));
		}
	}
}